"""它将定义在应用程序中使用的-."""
from user_agents import parse

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.sessions import SessionMiddleware

from core.plugin import (
    register_plugin_admin_menu, get_plugin_state_change_time,
    read_plugin_state, cache_plugin_state, cache_plugin_menu, register_plugin,
    unregister_plugin, delete_router_by_tagname
)
from core.settings import settings, cors_config


def regist_core_middleware(app: FastAPI) -> None:
# “向应用程序添加以下中间件。

# 中间件的执行顺序与代码的顺序相反。
# -在main.py的main_middleware（）之前运行。
# """

# #添加默认运行的core中间件。
    @app.middleware("http")
    async def core_middleware(request: Request, call_next):
        if not await should_run_middleware(request):
            return await call_next(request)

        # 插件设置
        plugin_state_change_time = get_plugin_state_change_time()
        if cache_plugin_state.__getitem__('change_time') != plugin_state_change_time:
#更改插件状态时更新缓存。
#更新后的管理员菜单，重新注册/删除路由器
            new_plugin_state = read_plugin_state()
            register_plugin(new_plugin_state)
            unregister_plugin(new_plugin_state)
            for plugin in new_plugin_state:
                if not plugin.is_enable:
                    delete_router_by_tagname(app, plugin.module_name)

            cache_plugin_menu.__setitem__('admin_menus', register_plugin_admin_menu(new_plugin_state))
            cache_plugin_state.__setitem__('change_time', plugin_state_change_time)
            cache_plugin_state.__setitem__('info', new_plugin_state)

        # 访问环境设置#连接首选参数
        request.state.is_mobile = False
        request.state.is_responsive = settings.IS_RESPONSIVE

        # 如果它的响应 PC/初始化移动版安装会话.#如果是响应式，请初始化PC/移动版本设置会话。
        if request.state.is_responsive:
            request.session["is_mobile"] = False
        else:
            # 由用户设置 PC/检查您的移动版设置会话.#验证用户设置的PC/移动版本设置会话。
            if request.session.get("is_mobile"):
                request.state.is_mobile = request.session.get("is_mobile", False)
            else:
                # User-Agent 标头确定它是否是移动的. (移动和平板电脑访问)#通过User-Agent标头判断是否移动。（移动和平板电脑连接）
                user_agent = parse(request.headers.get("User-Agent", ""))
                if user_agent.is_mobile or user_agent.is_tablet:
                    request.state.is_mobile = True

        # 设置设备默认值 #设置设备默认值
        request.state.device = "mobile" if request.state.is_mobile else "pc"

        # 将路由器设置为在中场可用.#在中间件中启用路由器。

        request.scope["router"] = app.router

        return await call_next(request)

#添加会话中间件。
#.env文件中的设置允许您设置secret_key、session_cookie。
    app.add_middleware(SessionMiddleware,
                       secret_key=settings.SESSION_SECRET_KEY,
                       session_cookie=settings.SESSION_COOKIE_NAME,
                       max_age=60 * 60 * 3)

#添加决定客户端使用的协议的中间件。
    # 添加一名中场球员以确定客户将使用哪种协议.
    app.add_middleware(BaseSchemeMiddleware)

    app.add_middleware(
        CORSMiddleware,
        allow_origins = cors_config.allow_origins,
        allow_credentials = cors_config.allow_credentials,
        allow_methods = cors_config.allow_methods,
        allow_headers = cors_config.allow_headers,
    )


async def should_run_middleware(request: Request) -> bool:
    """它决定中场是否会运行.

    对于下面的请求，我们不运行中场.
    - 生成令牌的请求
    - 请求固定文件 (css, js, 图像等。)

    Args:
        request (Request): FastAPI的 Request 对象

    Returns:
        bool: 是否要跑中场
    """
    path = request.url.path
    if (path.startswith('/generate_token')
            or path.startswith('/device/change')
            or path.startswith('/static')
            or path.startswith('/theme_static')
            or path.startswith('/data')
            or path.endswith(('.css', '.js', '.jpg', 'jpeg', '.png', '.gif', '.webp'))):
        return False

    return True


class BaseSchemeMiddleware(BaseHTTPMiddleware):
    """X-Forwarded-Proto 标头确定客户端使用的实际协议."""
    # “X-Forwarded-Proto标头确定客户端使用的实际协议。”
    async def dispatch(self, request: Request, call_next):
        request.scope["scheme"] = request.headers.get("X-Forwarded-Proto", "http")
        return await call_next(request)
